﻿using JNPF.Basics.Logic;
using JNPF.Basics.Models;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Diagnostics;
using System.Reflection;

namespace JNPF.Utils.Controller
{
    /// <summary>
    /// 请求拦截
    /// 版 本：V3.0.0
    /// 版 权：引迈信息技术有限公司（https://www.jnpfsoft.com）
    /// 作 者：JNPF开发平台组
    /// </summary>
    public class FilterRequest : ActionFilterAttribute
    {
        /// <summary>
        /// 计时器
        /// </summary>
        private Stopwatch stopwatch { get; set; }
        /// <summary>
        /// 请求前
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            //计时器（开始）
            stopwatch = CommonHelper.TimerStart();
            //XSS攻击防御过滤器
            //FilterScript(context);
        }
        /// <summary>
        /// 请求后
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override void OnActionExecuted(ActionExecutedContext context)
        {
            try
            {
                //请求写入日志
                RequestLog(context);
                stopwatch.Stop();
            }
            catch (Exception)
            {

                throw;
            }
        }

        #region XSS攻击防御过滤器
        /// <summary>
        /// XSS攻击防御过滤器
        /// </summary>
        /// <param name="context">context</param>
        private void FilterScript(ActionExecutingContext context)
        {
            if (context.HttpContext.Request.Method.ToLower().Equals("post"))
            {
                var ignoreCheckScript = (IgnoreCheckScriptAttribute)((ControllerActionDescriptor)context.ActionDescriptor).MethodInfo.GetCustomAttribute(typeof(IgnoreCheckScriptAttribute), false);
                if (ignoreCheckScript == null)
                {
                    var ps = context.ActionDescriptor.Parameters;
                    foreach (var p in ps)
                    {
                        if (context.ActionArguments[p.Name] != null)
                        {
                            if (p.ParameterType.Equals(typeof(string)))
                            {
                                context.ActionArguments[p.Name] = XSSHelper.XssFilter(context.ActionArguments[p.Name].ToString());
                            }
                            else if (p.ParameterType.IsClass)
                            {
                                PostModelFieldFilter(p.ParameterType, context.ActionArguments[p.Name]);
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// 遍历实体的字符串属性
        /// </summary>
        /// <param name="type">数据类型</param>
        /// <param name="obj">对象</param>
        /// <returns></returns>
        private object PostModelFieldFilter(Type type, object obj)
        {
            if (obj != null)
            {
                foreach (var item in type.GetProperties())
                {
                    if (item.GetValue(obj) != null)
                    {
                        //当参数是str
                        if (item.PropertyType.Equals(typeof(string)))
                        {
                            string value = item.GetValue(obj).ToString();
                            item.SetValue(obj, XSSHelper.XssFilter(value));
                        }
                        else if (item.PropertyType.IsClass)//当参数是一个实体
                        {
                            item.SetValue(obj, PostModelFieldFilter(item.PropertyType, item.GetValue(obj)));
                        }
                    }
                }
            }
            return obj;
        }
        #endregion

        #region 写入日志
        /// <summary>
        /// 写入日志
        /// </summary>
        /// <param name="context"></param>
        public void RequestLog(ActionExecutedContext context)
        {
            UserProvider userProvider = new UserProvider();
            if (userProvider.IsOverdue != false)
            {
                var httpContext = Utils.HttpContext.Current;
                var userInfo = userProvider.Get();
                if (userInfo == null)
                    return;
                var entity = new LogEntity
                {
                    Category = LogSortEnum.Request,
                    UserId = userInfo.UserId,
                    UserName = userInfo.UserName + "/" + userInfo.UserAccount,
                    PlatForm = Net.UserAgent,
                    RequestURL = context.ActionDescriptor.AttributeRouteInfo.Template.Split(new string[] { "/{" }, StringSplitOptions.None)[0],
                    RequestMethod = httpContext.Request.Method,
                    RequestDuration = CommonHelper.TimerEnd(stopwatch).ToInt(),
                    IPAddress = Net.Ip
                };
                LogBll.Instance.WriteLogAsync(entity);
            }
        }
        #endregion
    }
}